﻿using Lazy.Captcha.Core.Generator.Image;
using Lazy.Captcha.Core.Interface;
using WeDonekRpc.CacheClient.Interface;
using WeDonekRpc.Helper;

namespace Lazy.Captcha.Core.Service
{
    internal class VerCodeService : IVerCodeService
    {
        private readonly IVerCodeConfig _Config;

        private readonly IVerCodeRateLimit _RateLimit;
        private readonly ICacheController _Cache;
        private readonly ICaptchaImageGenerator _ImgGenerator;
        private readonly string _CacheKey;
        protected VerCodeService ( string cacheKey, IVerCodeConfig config,
            IVerCodeRateLimit rateLimit,
            ICacheController cache,
            ICaptchaImageGenerator imgGenerator )
        {
            this._CacheKey = cacheKey;
            this._Cache = cache;
            this._Config = config;
            this._RateLimit = rateLimit;
            this._ImgGenerator = imgGenerator;
        }

        public virtual byte[] Generate ( string captchaId )
        {
            this._RateLimit.IsAllowed(captchaId);
            (string renderText, string code) = this._Config.CodeGenerator.Generate();
            byte[] image = this._ImgGenerator.Generate(renderText, this._Config.ImageOption);
            string key = this._CacheKey + captchaId;
            if ( !this._Cache.Set(key, code, this._Config.ExpirySeconds) )
            {
                throw new ErrorException("hr.ver.code.save.fail");
            }
            return image;
        }
        public virtual void Validate ( string captchaId, string code, bool removeIfFail = true )
        {
            if ( code.IsNull() )
            {
                throw new ErrorException("hr.ver.code.null");
            }
            string key = this._CacheKey + captchaId;
            if ( !this._Cache.TryGet(key, out string verCode) )
            {
                throw new ErrorException("hr.ver.code.error");
            }
            else
            {
                StringComparison comparisonType = this._Config.IgnoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture;
                bool success = !string.IsNullOrWhiteSpace(code) && !string.IsNullOrWhiteSpace(verCode) && string.Equals(verCode, code, comparisonType);
                if ( !success )
                {
                    if ( removeIfFail )
                    {
                        _ = this._Cache.Remove(key);
                    }
                    throw new ErrorException("hr.ver.code.error");
                }
                _ = this._Cache.Remove(key);
            }
        }
    }
}
